<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>SVG</title>
    <script src="scripts/snap.svg.js"></script>
    <style>
        .node_name {
            font-size: 26px;
        }

        .node_timer_count {
            font-size: 30px;
            fill: wheat;
        }

        .node_term {
            font-size: 30px;
        }

        .node_timer {
            stroke-width: 8;
            stroke: darkblue;
            stroke-dasharray: 315, 315;
            stroke-dashoffset: 315;
            opacity: 0.5;
            fill: none
        }

        .dot {
            fill: none;
            stroke: #b5580d;
            stroke-width: 3;
        }

        .follower {
            fill: palevioletred;
            stroke: #b5580d;
            stroke-width: 8;
            opacity: 0.8
        }

        .candidate {
            fill: darkolivegreen;
            stroke: #b5580d;
            stroke-width: 8;
            opacity: 0.8
        }

        .leader {
            fill: rebeccapurple;
            stroke: #b5580d;
            stroke-width: 8;
            opacity: 0.8
        }

    </style>
</head>

<body>
<button id="button" onclick="next()">next</button>
<svg id="raft" width="1600" height="1600" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="rgb(255,150,200)">




<!--    <rect x="100" y="100" width="200" height="200" fill="blue" />-->
<!--    <circle cx="200" cy="200" r="50" stroke="yellow" stroke-width="40" stroke-opacity=".5" fill="red" />-->
<!--    <marker id="markerArrow" markerWidth="10" markerHeight="7"-->
<!--            refX="0" refY="3.5"  orient="auto" fill="black">-->
<!--        <polygon points="0 0, 10 3.5, 0 7" />-->
<!--    </marker>-->
<!--    <path id="markPath" d='M200,200 L800,200' stroke='#000' stroke-dasharray="5 5"  style="marker-end: url(#markerArrow);" stroke-width="3"></path>-->
<!--    <circle  r="20" fill="red">-->
<!--        <animateMotion id="motion" dur="1s" begin="0;motion.end">-->
<!--            <mpath xlink:href="#markPath"></mpath>-->
<!--        </animateMotion>-->
<!--        <animate id="goright" attributeType="XML" attributeName="cx"-->
<!--         from="200" to="800" dur="1s"   begin="0;goright.end+1s" fill="freeze"></animate>-->
<!--        <animate id="goleft" attributeType="XML" attributeName="cx"-->
<!--                 from="800" to="200" dur="1s" fill="freeze"  begin="goright.end"></animate>-->
<!--        <animate attributeType="xml" attributeName="fill" from="red" to="yellow" dur="3s" ></animate>-->
<!--    </circle>-->
    <g id="cluster" transform="translate(300 100)"/>

</svg>
    <script>
        snap = Snap('#raft');
        translates = [
            [200, 0], [0, 180], [400, 180], [80, 400], [320, 400]
        ]
        for (let i = 0; i < 5; i++) {
            let cluster_g = snap.select('#cluster');
            let node = `S${i}`;
            let node_g = cluster_g.g().attr({
                id: node,
                transform: `translate(${translates[i][0]} ${translates[i][1]})`
            });
            node_g.circle(50, 80, 50).addClass("follower");
            node_g.text(40, 65, "1").addClass("node_term");
            node_g.text(20, 95, "").addClass("node_timer_count");
            node_g.text(35, 122, node).addClass("node_name");
            node_g.path("M 50, 30 a 50,50 0 1,1 0,100 a 50,50 0 1,1 0,-100").addClass("node_timer");
        }

        let points = [
            [250, 150], [120, 260], [380, 260], [150, 410], [350, 410]
        ]


        function next(){
            let g = snap.select('#cluster').g();
            for (let i = 0; i < 5; i++) {
                for (let j = 0; j < 5; j++) {
                    if (i == j) continue;
                    let path = snap.path("M " + points[i][0] + "," + points[i][1]
                        + " L " + points[j][0] + "," + points[j][1])
                        .attr({"stroke": "blue", "stroke-dasharray": "5 10"});
                    g.add(path);
                    g.circle(points[i][0], points[i][1], 10)
                        .attr({id: `dot-${i}-${j}`, class: "dot"});
                }
            }
        }

        function reset_timer(node_g) {
            node_g.select(`.node_timer`).attr({"stroke-dashoffset": 315})
            node_g.select(`.node_timer_count`).attr({text: "0000"});
        }

        function update_state(msg, update_timer = true) {
            console.log('update state: ' + msg);
            let data = JSON.parse(msg);
            let node_g = snap.select(`#S${data.id}`);
            node_g.select(`circle`).attr({class: data.state});
            node_g.select(`.node_term`).attr({text: `${data.term}`});

            if (update_timer) {
                Snap.animate(0, data.timeout, function (value) {
                    node_g.select(`.node_timer_count`).attr({text: Math.round(data.timeout - value)});
                }, data.timeout);
                let timer = node_g.select(`.node_timer`);
                reset_timer(node_g);
                timer.animate({"stroke-dashoffset": 0},
                    data.timeout, mina.easeinout, reset_timer.bind(null, node_g));
            }
        }


        function reset_dot(dot, position) {
            console.log(position)
            dot.attr(position);
        }
        let leader={id:0,timeout:1000}
        function heartbeat() {
            for (let j = 0; j < 5; j++) {
                if (leader.id == j) continue;
                // console.log(leader)
                let dot = snap.select(`#dot-${leader.id}-${j}`);

                dot.animate(
                    {cx: points[j][0], cy: points[j][1]},
                    leader.timeout,
                    mina.linear,
                    reset_dot.bind(null, dot, {cx: points[leader.id][0], cy: points[leader.id][1]})
                );
            }
        }

        function interval() {
            let msg = '{"id":0,"class":"leader","term":"1","timeout":5000}';
            // update_state(msg);
            heartbeat();
        }
        function f() {
            let node_g = snap.select(`#S0`);
            let timer = node_g.select(`.node_timer`);
            Snap.animate(0, 100, function (value) {
                node_g.select(`.node_timer_count`).attr({text: Math.round(100 - value)});
            }, 1000);

            reset_timer(node_g);
            timer.animate({"stroke-dashoffset": 0},
                3000, mina.easeinout, reset_timer.bind(null, node_g));
        }
        next();
        // setInterval(interval, 2000);
        setInterval(f, 2000);
        let s = snap;
        let offset = 50;
        let g = s.g().attr({ stroke: 'gray' });
        for (let i = 0; i <=1600 / offset; i++) {
            g.line(i * offset, 0, i * offset, 1600)
                .attr({ "stroke-width": '1', "stroke-dasharray": "5, 5" });
            g.line(0, i * offset, 1600, i * offset)
                .attr({ "stroke-width": '1', "stroke-dasharray": "5, 5" });
            g.text(0, i * offset, i * offset);
            g.text(i * offset, 20, i * offset);
        }
    </script>
</body>

</html>